﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WinScriptEngine.Parses.Basic;
using WinScriptEngine.Parses.Impl;
using WinScriptEngine.Parses.Interface;

namespace WinScriptEngine.Parses.Scope
{
    class InvokeEnvironment
    {
        public const int DefaultOperLevel = int.MaxValue;
        public const int DefaultEip = default(int);
        public const int DefaultNeedNumber = 1;

        /// <summary>
        /// 当前执行环境中的符号
        /// </summary>
        public Symbols symbols = new();
        /// <summary>
        /// 计算时被压栈的运算结果
        /// </summary>
        public Stack<Metadata> results = new();
        /// <summary>
        /// 计算时被压栈的操作符
        /// </summary>
        public Stack<Operator> operators = new();
        /// <summary>
        /// 当前执行指令块
        /// </summary>
        public List<Metadata> instructions = new();
        /// <summary>
        /// 指令指针寄存器
        /// </summary>
        public int eip = DefaultEip;
        /// <summary>
        /// 当前需要几个参数可完成计算
        /// </summary>
        public int needNumber = DefaultNeedNumber;
        /// <summary>
        /// 当前运算符优先级
        /// </summary>
        public int operLevel = DefaultOperLevel;  
        /// <summary>
        /// 配置的解析器列表（解析顺序由前至后）
        /// </summary>
        static readonly IParse[] parses = new IParse[]{
                WhiteParseImpl.GetInstance(),
                NumberParseImpl.GetInstance(),
                StringParseImpl.GetInstance(),
                ControlParseImpl.GetInstance(),
                OperatorParseImpl.GetInstance(),
                SymbolParseImpl.GetInstance(),
            };
        /// <summary>
        /// 解析脚本字符串,解析的结果存放入<see cref="instructions"/>
        /// </summary>
        /// <param name="script">脚本字符串</param>
        public void Parse(string script)
        {
            IEnumerator<char> enumerator = script.GetEnumerator();
            enumerator.MoveNext();
            Metadata preValue = null;

            while (true)
            {
                try
                {
                    _ = enumerator.Current; // 对是否读到结尾进行判断（想尝试不用这种方式）
                }
                catch (Exception){break;}

                bool isParsed = false;
                // 轮询所有的解析器
                foreach (var parse in parses)
                {
                    if (!parse.TryParse(ref preValue, enumerator.Current))
                        continue;

                    isParsed = true;
                    Metadata curValue = parse.Parse(ref preValue, enumerator);
                    // 没有与解析字符串相关的值则跳过添加值的行为（如WhiteParseImpl）
                    if (curValue == null)  
                        break;

                    // 在这儿绑定解析器，执行时调用Invoke
                    if (curValue.parser == null) 
                        curValue.parser = parse;
                    instructions.Add(curValue);
                    preValue = curValue;
                    break;
                }
                if (!isParsed)
                    throw new UndefinedException("无法识别的字符");
            }
        }
        /// <summary>
        /// 执行解析后的脚本
        /// </summary>
        public void Invoke()
        {
            foreach (var item in instructions)
            {
                Console.WriteLine($"Type: {item.type,-10} Value: {item.@object}");
                item.parser.Invoke(this);
                ++eip;
            }
            this.operLevel = int.MaxValue;
            ClearOperatorCache();
            Console.WriteLine($"Result: {OperatorMethod.GetValue(this)}");
            ClearInstruction();
        }
        /// <summary>
        /// 清除当前执行数据（除了符号）
        /// </summary>
        /// <returns>清除过程中是否出现错误（废弃）</returns>
        public bool ClearInstruction()
        {
            this.instructions.Clear();
            this.operators.Clear();
            this.results.Clear();
            this.needNumber = DefaultNeedNumber;
            this.eip = DefaultEip;
            this.operLevel = DefaultOperLevel;
            return true;
        }
        /// <summary>
        /// 清除低于当前优先级的所有运算符缓存，并计算运算符
        /// </summary>
        /// <returns>清除过程中是否出现错误（废弃）</returns>
        public bool ClearOperatorCache()
        {
            while (this.operators.Count > 0)
            {
                Operator @operator = this.operators.First();
                if (@operator == null || @operator.CompareLevel(this.operLevel) < 0)
                    break;

                @operator.operatorCallback(this);
                this.operators.Pop();
            }
            return true;
        }
    }
}
